package com.ruoyix.aicode.util;

import cn.hutool.extra.pinyin.PinyinUtil;
import com.fasterxml.jackson.databind.ObjectMapper;

import com.ruoyix.aicode.domain.PageSection;
import com.ruoyix.aicode.domain.PageStyle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 代码生成工具类
 */
public class CodeGenerationUtil {
    private static final Logger logger = LoggerFactory.getLogger(CodeGenerationUtil.class);
    private static final ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 构建分析需求的提示词
     *
     * @param requirements 需求
     * @return 分析提示词
     */
    public static String buildAnalysisPrompt(String requirements) {
        String prompt = String.format("""
            作为一个专业的前端UI/UX设计师和开发者，请分析以下需求，设计一个美观、现代且用户友好的前端页面结构。

            需求：%s

            请按照以下步骤设计页面结构：
            1. 首先分析需求，确定页面的核心功能和用户目标
            2. 设计清晰的页面布局，使用Bootstrap栅格系统(row和col-*)组织内容
            3. 确保页面结构符合现代设计趋势，包括足够的留白、清晰的视觉层次和直观的信息架构

            返回的HTML结构必须：
            1. 使用Bootstrap 5栅格系统
            2. 为每个主要区域创建清晰的SECTION标记
            3. 考虑响应式设计，在不同屏幕尺寸上有合理的布局
            4. 包含必要的容器元素，确保内容正确对齐和间距

            请使用以下格式标记每个区域（确保开闭标签配对）：

            <!-- SECTION: 区域名称 -->
            <div class="container[或container-fluid] my-4">
              <div class="row">
                <div class="col-适当的尺寸">
                  <!-- 这里将放置区域内容 -->
                </div>
              </div>
            </div>
            <!-- /SECTION: 区域名称 -->

            请直接返回完整的页面结构HTML，不需要添加任何说明或额外标记。确保所有SECTION标记都有配对的开始和结束标签。
            """, requirements);
        logger.debug("分析需求提示词: {}", prompt);
        return prompt;
    }

    /**
     * 构建Vue+Element Plus页面分析的提示词
     *
     * @param requirements 需求
     * @return 分析提示词
     */
    public static String buildVueAnalysisPrompt(String requirements) {
        String prompt = String.format("""
            作为一个专业的Vue前端UI/UX设计师和开发者，请分析以下需求，设计一个美观、现代且用户友好的Vue页面结构。

            需求：%s

            请按照以下步骤设计页面结构：
            1. 首先分析需求，确定页面的核心功能和用户目标
            2. 设计清晰的页面布局，使用Element Plus栅格系统(el-row和el-col)组织内容
            3. 确保页面结构符合现代设计趋势，包括足够的留白、清晰的视觉层次和直观的信息架构

            返回的Vue结构必须：
            1. 使用Element Plus栅格系统，
            2. 为每个主要区域创建清晰的SECTION标记
            3. 考虑响应式设计，使用Element Plus提供的:xs、:sm、:md、:lg、:xl属性适配不同屏幕尺寸
            4. 包含必要的容器元素，确保内容正确对齐和间距
            5. 使用Vue的单文件组件格式(.vue文件结构)
            6. 考虑响应式设计，在不同屏幕尺寸上有合理的布局
            7. 不要有最外层的<template>标签,只使用Element Plus栅格系统，其他使用html标签
            8.不要使用vue变量，因为还都没有定义

            请使用以下格式标记每个区域（确保开闭标签配对）：

            <!-- SECTION: 区域名称 -->
              <div class="container>
                <el-row :gutter="20">
                  <el-col :span="相应的列宽" :xs="小屏幕宽度" :sm="中屏幕宽度" :md="适当的宽度" :lg="大屏幕宽度">
                    <!-- 这里将放置区域内容 -->
                  </el-col>
                </el-row>
              </div>
            <!-- /SECTION: 区域名称 -->

            请直接返回完整的Vue页面结构，不需要添加任何说明或额外标记。确保所有SECTION标记都有配对的开始和结束标签。每个区域需要考虑其在整体页面中的位置和功能，合理安排Element Plus组件。
            """, requirements);
        logger.debug("Vue页面分析需求提示词: {}", prompt);
        return prompt;
    }

    /**
     * 构建单个组件的提示词
     *
     * @param requirements 需求
     * @param section 页面部分
     * @param pageStyle 页面风格
     * @param useGlobalContext 是否使用全局上下文
     * @param skeletonCode 骨架代码
     * @param generatedComponents 已生成组件
     * @return 组件提示词
     */
    public static String buildSingleComponentPrompt(String requirements, PageSection section,
                                                    PageStyle pageStyle, boolean useGlobalContext,
                                                    StringBuilder skeletonCode,
                                                    Map<String, String> generatedComponents) {
        // 获取骨架代码的相关部分
        String relevantSkeletonPart = extractRelevantSkeletonPart(section.getId(), skeletonCode);

        // 获取已生成组件的样式代码，作为参考
        String generatedStyles = extractGeneratedStyles(generatedComponents);

        // 获取页面整体结构摘要
        String skeletonSummary = generateSkeletonSummary(skeletonCode);

        String prompt = String.format("""
            作为一个专业的前端UI/UX设计师和开发者，请为'%s'部分创建一个美观、功能完整的组件。

            页面需求：%s

            页面风格：%s

            你正在生成的是整个页面中的'%s'组件。请确保这个组件：
            1. 设计精美，符合%s风格
            2. 功能完整，满足该部分的用户需求
            3. 响应式设计，在各种设备上都能良好显示
            4. 与整体页面风格协调一致

            技术要求：
            1. 使用%s框架的栅格系统和组件
            2. 使用Font Awesome图标
            3. 添加适当的动画效果增强用户体验
            4. 确保代码整洁、语义化且易于维护
            5. 使用CSS变量保持样式一致性(--primary-color, --secondary-color等)

            页面整体结构摘要：
            %s

            已生成组件的样式参考：
            %s

            请按照以下结构返回代码：

            <!-- 组件HTML结构 -->
            <div class="section-%s section-container">
              <!-- 组件内容，使用%s栅格系统和组件 -->
            </div>

            <style>
            /* 组件专用样式，使用CSS变量确保一致性 */
            .section-%s {
              /* 样式定义 */
            }
            </style>

            <script>
            // 组件专用JavaScript，使用现代ES6+语法
            document.addEventListener('DOMContentLoaded', function() {
              // 组件初始化代码
            });
            </script>

            设计指南：
            1. 使用卡片、阴影和圆角创建现代感
            2. 合理使用留白增强可读性
            3. 使用动画提升用户体验，但不要过度
            4. 确保文本对比度满足可访问性要求
            5. 使用一致的颜色方案(主要使用CSS变量中定义的颜色)
            6. 所有涉及图片使用的url都使用占位图片服务，如：https://picsum.photos/300/200

            如果这是一个包含子组件的父组件，请为子组件预留适当的位置，使用注释标记。

            %s

            直接输出代码，不需要任何解释或标记。
            """,
            section.getId(),
            requirements,
            pageStyle.getDescription(),
            section.getId(),
            pageStyle.getColorScheme(),
            pageStyle.getUiFramework(),
            skeletonSummary,
            generatedStyles,
            PinyinUtil.getPinyin(section.getId(), ""),
            pageStyle.getUiFramework(),
            PinyinUtil.getPinyin(section.getId(), ""),
            useGlobalContext ? "请考虑整个页面的上下文和其他组件的风格，确保一致性。" : "专注于当前组件的功能和设计，不需要考虑其他组件。");

        logger.debug("组件提示词: {}", prompt);
        return prompt;
    }

    /**
     * 构建通用组件提示词
     *
     * @param requirements 需求
     * @return 通用组件提示词
     */
    public static String buildGenericComponentsPrompt(String requirements) {
        String prompt = String.format("""
            作为一个专业的前端开发者，请根据以下需求生成页面所需的各个部分代码：

            需求：%s

            请为页面的每个部分生成完整的HTML代码，每个部分使用以下格式：

            <!-- SECTION: 部分名 -->
            <div class="section-name">
              <!-- 部分内容 -->
            </div>
            <style>
            /* 部分样式 */
            </style>
            <script>
            // 部分脚本
            </script>

            请确保：
            1. 每个部分都有明确的功能和职责
            2. 部分之间有清晰的结构和布局
            3. 样式美观，符合现代UI设计
            4. 代码可维护性高，有必要的注释
            5. 使用纯HTML、CSS和JavaScript
            6. 只输出纯HTML代码，不要包含任何说明、标记或代码块符号
            7. 不要使用```html或```等标记
            8. 分别生成以下部分，每个部分都用上面的格式：
               - 页面头部（Header）
               - 导航菜单（Navigation）
               - 主要内容区（MainContent）
               - 侧边栏（Sidebar，如需要）
               - 页脚（Footer）

            直接生成代码，不需要任何额外的标记或说明。
            """, requirements);
        logger.debug("通用组件提示词: {}", prompt);
        return prompt;
    }

    /**
     * 从组件内容中提取指定部分
     *
     * @param componentContent 组件内容
     * @param partType 部分类型 (body, style, script)
     * @return 提取的部分内容
     */
    public static String extractComponentPart(String componentContent, String partType) {
        try {
            String result = "";

            switch (partType) {
                case "body":
                    // 提取HTML部分 - 假设组件内容以<div开头，到<style>之前
                    int stylePos = componentContent.indexOf("<style>");
                    if (stylePos == -1) {
                        stylePos = componentContent.indexOf("<script>");
                    }
                    if (stylePos == -1) {
                        stylePos = componentContent.length();
                    }
                    result = componentContent.substring(0, stylePos).trim();
                    break;

                case "style":
                    // 提取样式部分 - 在<style>和</style>之间
                    int styleStart = componentContent.indexOf("<style>");
                    int styleEnd = componentContent.indexOf("</style>");
                    if (styleStart != -1 && styleEnd > styleStart) {
                        result = componentContent.substring(styleStart + "<style>".length(), styleEnd).trim();
                    }
                    break;

                case "script":
                    // 提取脚本部分 - 在<script>和</script>之间
                    int scriptStart = componentContent.indexOf("<script>");
                    int scriptEnd = componentContent.indexOf("</script>");
                    if (scriptStart != -1 && scriptEnd > scriptStart) {
                        result = componentContent.substring(scriptStart + "<script>".length(), scriptEnd).trim();
                    }
                    break;
            }

            return result;
        } catch (Exception e) {
            logger.error("提取组件 {} 部分时出错: {}", partType, e.getMessage(), e);
            return "";
        }
    }

    /**
     * 从脚本中提取初始化代码（DOMContentLoaded事件内的代码）
     *
     * @param scriptContent 脚本内容
     * @return 初始化代码
     */
    public static String extractInitCode(String scriptContent) {
        // 尝试查找DOMContentLoaded事件
        Pattern domReadyPattern = Pattern.compile("document\\.addEventListener\\('DOMContentLoaded', function\\(\\)\\s*\\{([\\s\\S]*?)\\}\\);", Pattern.CASE_INSENSITIVE);
        Matcher domReadyMatcher = domReadyPattern.matcher(scriptContent);

        if (domReadyMatcher.find()) {
            return domReadyMatcher.group(1).trim();
        }

        // 如果没有找到事件监听器，返回不包含函数定义的代码
        String[] lines = scriptContent.split("\n");
        StringBuilder initCode = new StringBuilder();

        for (String line : lines) {
            if (!line.trim().startsWith("function ") &&
                !line.contains(" function(") &&
                !line.contains(" function (")) {
                initCode.append(line).append("\n");
            }
        }

        return initCode.toString().trim();
    }

    /**
     * 从脚本中提取函数定义
     *
     * @param scriptContent 脚本内容
     * @return 函数定义
     */
    public static String extractFunctions(String scriptContent) {
        String[] lines = scriptContent.split("\n");
        StringBuilder functions = new StringBuilder();
        boolean inFunction = false;
        int braceCount = 0;

        for (String line : lines) {
            // 检测函数开始
            if (!inFunction && (line.trim().startsWith("function ") ||
                               line.contains(" function(") ||
                               line.contains(" function ("))) {
                inFunction = true;
                braceCount = countChar(line, '{') - countChar(line, '}');
                functions.append(line).append("\n");
                continue;
            }

            // 在函数内部
            if (inFunction) {
                functions.append(line).append("\n");
                braceCount += countChar(line, '{') - countChar(line, '}');

                // 检测函数结束
                if (braceCount <= 0) {
                    inFunction = false;
                }
            }
        }

        return functions.toString().trim();
    }

    /**
     * 计算字符在字符串中出现的次数
     *
     * @param str 字符串
     * @param c 字符
     * @return 出现次数
     */
    public static int countChar(String str, char c) {
        int count = 0;
        for (int i = 0; i < str.length(); i++) {
            if (str.charAt(i) == c) {
                count++;
            }
        }
        return count;
    }

    /**
     * 提取已生成组件的样式代码
     *
     * @param generatedComponents 已生成组件映射
     * @return 样式代码
     */
    public static String extractGeneratedStyles(Map<String, String> generatedComponents) {
        StringBuilder styles = new StringBuilder();

        for (Map.Entry<String, String> entry : generatedComponents.entrySet()) {
            String componentName = entry.getKey();
            String componentCode = entry.getValue();

            String styleCode = extractComponentPart(componentCode, "style");
            if (styleCode != null && !styleCode.isEmpty()) {
                styles.append("/* ").append(componentName).append(" 样式 */\n");
                styles.append(styleCode).append("\n\n");
            }
        }

        // 如果没有已生成的样式，返回默认样式指南
        if (styles.length() == 0) {
            styles.append("/* 推荐使用CSS变量保持一致性 */\n");
            styles.append("/* --primary-color: #3498db; */\n");
            styles.append("/* --secondary-color: #2ecc71; */\n");
            styles.append("/* --accent-color: #e74c3c; */\n");
        }

        return styles.toString();
    }

    /**
     * 生成骨架代码摘要
     *
     * @param skeletonCode 骨架代码
     * @return 摘要
     */
    public static String generateSkeletonSummary(StringBuilder skeletonCode) {
        if (skeletonCode.length() == 0) {
            return "页面骨架尚未生成";
        }

        // 提取主要结构，忽略详细内容
        String skeleton = skeletonCode.toString();
        StringBuilder summary = new StringBuilder();

        // 提取body内的主要div结构
        Pattern bodyPattern = Pattern.compile("<body[^>]*>(.*?)</body>", Pattern.DOTALL);
        Matcher bodyMatcher = bodyPattern.matcher(skeleton);

        if (bodyMatcher.find()) {
            String bodyContent = bodyMatcher.group(1);

            // 提取主要容器和行
            Pattern containerPattern = Pattern.compile("<div class=\"container[^\"]*\"[^>]*>|<div class=\"row\"[^>]*>|<div class=\"col[^\"]*\"[^>]*>", Pattern.DOTALL);
            Matcher containerMatcher = containerPattern.matcher(bodyContent);

            while (containerMatcher.find() && summary.length() < 500) {
                summary.append(containerMatcher.group()).append("\n  ...\n</div>\n");
            }
        }

        if (summary.length() == 0) {
            return "简洁的Bootstrap布局结构";
        }

        return summary.toString();
    }

    /**
     * 从骨架代码中提取与特定组件相关的部分
     *
     * @param sectionId 部分ID
     * @param skeletonCode 骨架代码
     * @return 相关部分代码
     */
    public static String extractRelevantSkeletonPart(String sectionId, StringBuilder skeletonCode) {
        if (skeletonCode.length() == 0) {
            return "骨架代码尚未生成";
        }

        String skeleton = skeletonCode.toString();
        String startTag = "<!-- SECTION: " + sectionId + ":start -->";
        String endTag = "<!-- SECTION: " + sectionId + ":end -->";

        int startPos = skeleton.indexOf(startTag);
        int endPos = skeleton.indexOf(endTag);

        if (startPos >= 0 && endPos > startPos) {
            // 提取包含标签的部分
            return skeleton.substring(startPos, endPos + endTag.length());
        }

        // 如果找不到精确匹配，尝试查找更宽松的匹配
        startTag = "<!-- SECTION: " + sectionId;
        startPos = skeleton.indexOf(startTag);

        if (startPos >= 0) {
            // 提取包含标签的行及其周围几行
            int contextStart = Math.max(0, skeleton.lastIndexOf("\n", startPos));
            int contextEnd = skeleton.indexOf("\n", startPos + 50);
            if (contextEnd < 0) contextEnd = skeleton.length();

            return skeleton.substring(contextStart, contextEnd);
        }

        return "在骨架代码中未找到相关部分";
    }

    /**
     * 解析页面结构
     *
     * @param analysisContent 分析内容
     * @param pageSections 页面部分列表
     */
    public static void parsePageStructure(String analysisContent, List<PageSection> pageSections) {
        // 改进的正则表达式：匹配SECTION标记对
        Pattern sectionPattern = Pattern.compile(
            "<!--\\s*SECTION:\\s*([^>]+?)\\s*-->([\\s\\S]*?)<!--\\s*/SECTION:\\s*\\1\\s*-->",
            Pattern.DOTALL
        );

        Matcher sectionMatcher = sectionPattern.matcher(analysisContent);
        Map<String, PageSection> sectionMap = new java.util.HashMap<>();

        // 第一遍：收集所有顶级部分
        while (sectionMatcher.find()) {
            String sectionId = sectionMatcher.group(1).trim();
            String sectionContent = sectionMatcher.group(2);

            // 创建部分对象
            PageSection section = new PageSection(sectionId);
            sectionMap.put(sectionId, section);

            // 暂时添加到顶级部分列表
            pageSections.add(section);
        }

        // 第二遍：处理嵌套关系
        sectionMatcher.reset();
        while (sectionMatcher.find()) {
            String parentId = sectionMatcher.group(1).trim();
            String sectionContent = sectionMatcher.group(2);

            // 在内容中查找嵌套的部分
            Pattern nestedPattern = Pattern.compile(
                "<!--\\s*SECTION:\\s*([^>]+?)\\s*-->([\\s\\S]*?)<!--\\s*/SECTION:\\s*\\1\\s*-->",
                Pattern.DOTALL
            );
            Matcher nestedMatcher = nestedPattern.matcher(sectionContent);

            while (nestedMatcher.find()) {
                String childId = nestedMatcher.group(1).trim();

                // 如果在映射中找到子部分
                if (sectionMap.containsKey(childId) && sectionMap.containsKey(parentId)) {
                    PageSection childSection = sectionMap.get(childId);
                    PageSection parentSection = sectionMap.get(parentId);

                    // 从顶级列表中移除子部分
                    pageSections.remove(childSection);

                    // 添加到父部分的子列表中
                    parentSection.addChild(childSection);
                }
            }
        }
    }

    /**
     * 构建Vue+Element Plus单个组件的提示词
     *
     * @param requirements 需求
     * @param section 页面部分
     * @param pageStyle 页面风格
     * @param useGlobalContext 是否使用全局上下文
     * @param skeletonCode 骨架代码
     * @param generatedComponents 已生成组件
     * @return 组件提示词
     */
    public static String buildVueComponentPrompt(String requirements, PageSection section,
                                               PageStyle pageStyle, boolean useGlobalContext,
                                               StringBuilder skeletonCode,
                                               Map<String, String> generatedComponents) {
        // 获取骨架代码的相关部分
        String relevantSkeletonPart = extractRelevantSkeletonPart(section.getId(), skeletonCode);

        // 获取已生成组件的样式代码，作为参考
        String generatedStyles = extractGeneratedStyles(generatedComponents);

        // 获取页面整体结构摘要
        String skeletonSummary = generateSkeletonSummary(skeletonCode);

        String prompt = String.format("""
            作为一个专业的Vue前端UI/UX设计师和开发者，请为'%s'部分创建一个美观、功能完整的Vue组件。

            页面需求：%s

            页面风格：%s

            页面骨架: %s

            你正在生成的是整个页面中的'%s'组件。请确保这个组件：
            1. 设计精美，符合%s风格
            2. 功能完整，满足该部分的用户需求
            3. 响应式设计，在各种设备上都能良好显示
            4. 与整体页面风格协调一致

            技术要求：
            1. 使用Vue 3组合式API (composition API)
            2. 使用Element Plus组件库的栅格系统
            3. 添加适当的动画效果增强用户体验
            4. 确保代码整洁、语义化且易于维护
            5. 使用CSS变量保持样式一致性(--primary-color, --secondary-color等)
            6. 不需要生成路由相关功能
            7. 不要使用import语句导入其他组件
            8. 所有变量名必须使用单个前缀 例如导航栏的变量以header开头 const headerTitle = ref('')
            9. 函数名也使用相同前缀（如导航栏相关方法以header开头：const headerHandleClick = () => {}）

            页面整体结构摘要：
            %s

            已生成组件的样式参考：
            %s

            请按照以下结构返回Vue单文件组件代码：

            <template>
              <div class="section-%s">
                <!-- 使用Element Plus组件和栅格系统构建UI -->
                <el-row :gutter="20">
                  <el-col :span="24" :md="12">
                    <!-- 组件内容 -->
                  </el-col>
                </el-row>
              </div>
            </template>

            <script setup>

            // 生命周期钩子
            onMounted(() => {
              // 初始化代码
            });

            // 方法定义
            const handleEvent = () => {
              // 处理逻辑
            };
            </script>

            <style scoped>
            /* 组件专用样式，使用CSS变量确保一致性 */
            .section-%s {
              /* 样式定义 */
            }
            </style>

            设计指南：
            1. 合理使用留白增强可读性
            2. 确保文本对比度满足可访问性要求
            3. 使用一致的颜色方案(主要使用CSS变量中定义的颜色)
            4. 所有涉及图片使用的url都使用占位图片服务，如：https://picsum.photos/300/200
            5. 使用卡片、阴影和圆角创建现代感，通过css实现

            如果这是一个包含子组件的父组件，请为子组件预留适当的位置，使用注释标记。
            重点:在<script>中不要使用任何import语句,包括ref，ref可以直接使用，不需要import

            %s

            直接输出代码，不需要任何解释或标记。
            """,
            section.getId(),
            requirements,
            pageStyle.getDescription(),
            relevantSkeletonPart,
            section.getId(),
            pageStyle.getColorScheme(),
            skeletonSummary,
            generatedStyles,
            PinyinUtil.getPinyin(section.getId(), ""),
            PinyinUtil.getPinyin(section.getId(), ""),
            useGlobalContext ? "请考虑整个页面的上下文和其他组件的风格，确保一致性。" : "专注于当前组件的功能和设计，不需要考虑其他组件。");

        logger.debug("Vue组件提示词: {}", prompt);
        return prompt;
    }
}
